/*
 * socket_interface.c
 *
 *  Created on: 04/01/2013
 *      Author: Julian Ovalle
 */

#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <netdb.h>

#include "cli_message_def.h"
#include "socket_interface.h"

int openSocket() {

    int s = -1;

    struct servent *serv;
    serv = getservbyname(SOCKET_SERVICE_NAME, "tcp");

    printf("\nPuerto: %d", htons(serv->s_port));

    struct hostent *host;
    host = gethostbyname(SERVER_SOCKET_NAME);

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
#ifdef SOCK_INTERFACE_DEBUG
        perror("openSocket.Error abriendo socket");
#endif
        return -1;
    }

    struct sockaddr_in servAddr;
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
    servAddr.sin_port = serv->s_port;

    if (connect(s, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0) {
    #ifdef SOCK_INTERFACE_DEBUG
            perror("openSocket.error al conectar");
    #endif
            return -1;
        }

    return s;
}

void flushSocket (int s) {

    char str[20];
    int r = 1;

    while (r > 0) {
        r = socketReceive(s, str, 20, NULL, 0, 0, 10);
#ifdef SOCK_INTERFACE_DEBUG
        printf("\nflush: %s\n", str); //may not discard using recv
#endif
    }
}

int socketSend(int sfd, const void* data, size_t size, struct sockaddr* addr,
        socklen_t addrlen, int timeout_s, int timeout_ms) {

    struct timeval timeout;
    int r = -2;
    fd_set set;
    timeout.tv_sec = timeout_s;
    timeout.tv_usec = timeout_ms * 1000;
    FD_ZERO(&set);
    FD_SET(sfd, &set);

    if (select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0) {
        r = sendto(sfd, (char*) data, size, 0,
                (const struct sockaddr *) addr, (socklen_t) addrlen);
        if (r == -1) {
            return (-1);
#ifdef SOCK_INTERFACE_DEBUG
            perror("socketSend.sendto");
#endif
        } else {
            return r;
        }
    } else {
#ifdef SOCK_INTERFACE_DEBUG
        fprintf(stderr, "socketSend.sendto.timeout\n");
#endif
        return (-2);
    }
}

int socketReceive(int sfd, const void* buf, size_t size, struct sockaddr* addr,
        socklen_t addrlen, int timeout_s, int timeout_ms) {
    int r = -2;
    struct timeval timeout;
    fd_set set;

    timeout.tv_sec = timeout_s;
    timeout.tv_usec = timeout_ms * 1000;
    FD_ZERO(&set);
    FD_SET(sfd, &set);

    if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) {
        r = recvfrom(sfd, (char *) buf, size, 0, (const struct sockaddr *) addr,
                (socklen_t*) addrlen);
        if (r < 0) {
#ifdef SOCK_INTERFACE_DEBUG
            fprintf(stderr, "\nnsocketReceive.error in socket");
#endif
            return (-1);
        } else {
            return r;
        }
    } else {
#ifdef SOCK_INTERFACE_DEBUG
        fprintf(stderr, "nsocketReceive.rcvfrom.timeout\n");
#endif
        return (-2);
    }
}

